﻿using System;
using System.Collections.Generic;
using System.Linq;
using MIAP.DataAccess.Interfaces;
using MIAP.DataAccess.SqlServer.Model;
using MIAP.Entidades;
using MIAP.Entidades.Enums;

namespace MIAP.DataAccess.Implementaciones.SQL
{
    /// <summary>
    /// Clase de las operaciones de acceso a datos de la vista Perfiles.
    /// </summary>
    public class PerfilesDao : IPerfilesDao
    {
        /// <summary>
        /// Obtiene una lista de perfiles con los parametros indicados si no se requiere filtrar por ese parámetro enviar null.
        /// </summary>
        /// <param name="idPerfil">Id del perfl  a filtrar.</param>
        /// <param name="idProyecto">Id del proyecto al que pertenece el perfil</param>
        /// <param name="nombre">Nombre del perfil.</param>
        /// <param name="estaActivo">Indicador de estatus.</param>
        /// <returns></returns>
        private IList<PerfilInfo> GetPerfilesInterno(int? idPerfil, int? idProyecto, string nombre, bool? estaActivo)
        {
            IList<PerfilInfo> result;

            using (var context = new MIAPDBEntities())
            {
                var query = from miapPerfil in context.MIAP_PERFIL
                            where (!idPerfil.HasValue || miapPerfil.ID_PERFIL == idPerfil.Value)
                            && (!idProyecto.HasValue || miapPerfil.ID_PROYECTO == idProyecto.Value)
                            && (string.IsNullOrEmpty(nombre) || miapPerfil.NOMBRE.Contains(nombre))
                            && (!estaActivo.HasValue || miapPerfil.ACTIVO == estaActivo.Value)
                            select new PerfilInfo
                                {
                                    IdPerfil = miapPerfil.ID_PERFIL,
                                    EstaActivo = miapPerfil.ACTIVO,
                                    Proyecto = new ProyectoInfo
                                    {
                                        IDProyecto = miapPerfil.ID_PROYECTO.HasValue ? miapPerfil.MIAP_PROYECTO.ID_PROYECTO : 0
                                        ,
                                        NombreProyecto = miapPerfil.MIAP_PROYECTO.NOMBRE
                                    },
                                    Descripcion = miapPerfil.DESCRIPCION,
                                    NombrePerfil = miapPerfil.NOMBRE,
                                    FechaCreacion = miapPerfil.FECHA_CREACION
                                };

                result = query.ToList();

            }

            return result;
        }

        /// <summary>
        /// Obtiene todos los perfiles.
        /// </summary>
        /// <returns>Lista con todos los perfiles.</returns>
        public IList<PerfilInfo> GetPerfiles()
        {
            return this.GetPerfilesInterno(null, null, null, null);
        }

        /// <summary>
        /// Cambia el estatus del perfil a activo o inactivo.
        /// </summary>
        /// <param name="idPerfil">Es el id del perfil del cual se cambiará el estatus.</param>
        /// <param name="estatusRegistro">True (Activo), False (Inactivo)</param>
        public void ChangeEstatusPerfil(int idPerfil, bool estatusRegistro)
        {
            using (var context = new MIAPDBEntities())
            {
                var query = (from miapPerfil in context.MIAP_PERFIL
                             where miapPerfil.ID_PERFIL == idPerfil
                             select miapPerfil).SingleOrDefault();
                if (query == null) return;

                query.ACTIVO = estatusRegistro;
                context.SaveChanges();
            }
        }

        /// <summary>
        /// Obtiene la información de un determinado perfil.
        /// </summary>
        /// <param name="idPerfil">Es el id del perfil del que se desea obtener la informacion.</param>
        /// <returns>Información general del perfil.</returns>
        public PerfilInfo GetPerfilById(int idPerfil)
        {
            return this.GetPerfilesInterno(idPerfil, null, null, null).SingleOrDefault();
        }

        /// <summary>
        /// Obtiene la información de un determinado perfil.
        /// </summary>
        /// <param name="idProyecto">Id del proyecto al que pertenece.</param>
        /// <param name="nombre">Es el nombre del perfil.</param>
        /// <param name="estaActivo">Si el perfil esta activo o no.</param>
        /// <returns>Información general del perfil.</returns>
        public IList<PerfilInfo> GetPerfil(int? idProyecto, string nombre, bool? estaActivo)
        {
            return this.GetPerfilesInterno(null, idProyecto, nombre, estaActivo);
        }

        /// <summary>
        /// Obtiene todos los permisos ligados a un perfil.
        /// </summary>
        /// <param name="idPerfil">Id del perfil.</param>
        /// <returns>Lista de permisos ligados a un perfil.</returns>
        public IList<PermisoInfo> GetPermisosByIdPerfil(int idPerfil)
        {
            IList<PermisoInfo> result;

            using (var context = new MIAPDBEntities())
            {
                var permisos = (from perfilInfo in context.MIAP_PERFIL_URL_PERFIL
                                where perfilInfo.ID_PERFIL == idPerfil
                                select new PermisoInfo
                                    {
                                        Identificador = perfilInfo.MIAP_PERFIL_URL.ID_PERFIL_URL,
                                        PerfilUrl = new PerfilUrlInfo { IdPerfilUrl = perfilInfo.MIAP_PERFIL_URL.ID_PERFIL_URL },
                                        Nombre = perfilInfo.MIAP_PERFIL_URL.NOMBRE,
                                        Url = perfilInfo.MIAP_PERFIL_URL.URL
                                    }).ToList();
                result = permisos;
            }

            return result;
        }

        /// <summary>
        /// Obtiene los roles de un usuario.
        /// </summary>
        /// <param name="idUsuario">Es el id del usuario.</param>
        /// <returns>Lista de roles pertenecientes al usuario.</returns>
        public IList<PerfilInfo> GetPerfilByIdUsuario(int idUsuario)
        {
            IList<PerfilInfo> result;

            using (var context = new MIAPDBEntities())
            {
                var query = (from usuarioPerfil in context.MIAP_USUARIO_PERFIL
                             join perfil in context.MIAP_PERFIL on usuarioPerfil.ID_PERFIL equals perfil.ID_PERFIL
                             where usuarioPerfil.ID_USUARIO == idUsuario
                             select new PerfilInfo
                             {
                                 IdPerfil = perfil.ID_PERFIL,
                                 NombrePerfil = perfil.NOMBRE,
                                 Descripcion = perfil.DESCRIPCION,
                                 Proyecto = new ProyectoInfo { IDProyecto = perfil.ID_PROYECTO ?? 0 }
                             }).ToList();
                result = query;
                // Asignamos el proyecto al perfil
                if (result.Any())
                {
                    foreach (var perfilInfo in result)
                    {
                        perfilInfo.Proyecto = (from proyecto in context.MIAP_PROYECTO
                                               where proyecto.ID_PROYECTO == perfilInfo.Proyecto.IDProyecto
                                               select new ProyectoInfo
                                               {
                                                   IDProyecto = proyecto.ID_PROYECTO,
                                                   NombreProyecto = proyecto.NOMBRE,
                                                   Descripcion = proyecto.DESCRIPCION,
                                                   Estatus = proyecto.ACTIVO ? "Activo" : "Inactivo",
                                                   FechaActualizacion = proyecto.FECHA_ACTUALIZACION,
                                                   FechaCreacion = proyecto.FECHA_CREACION,
                                                   PaqueteCarga = proyecto.PAQUETE_CARGA,
                                                   PeriodoCarga = new PeriodoInfo
                                                   {
                                                       IdentificadorPeriodo =
                                                          proyecto.MIAP_PERIODO_CARGA.ID_PERIODO_CARGA,
                                                       NombrePeriodo = proyecto.MIAP_PERIODO_CARGA.NOMBRE,
                                                       TipoPeriodo = TipoPeriodo.Carga
                                                   },
                                                   PeriodoInformacion = new PeriodoInfo
                                                   {
                                                       IdentificadorPeriodo =
                                                           proyecto.MIAP_PERIODO_INFORMACION.ID_PERIODO_INFORMACION,
                                                       NombrePeriodo = proyecto.MIAP_PERIODO_INFORMACION.NOMBRE,
                                                       TipoPeriodo = TipoPeriodo.Carga
                                                   }
                                               }).Single();
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Agrega un nuevo perfil.
        /// </summary>
        /// <param name="perfil">Es el perfil que será agregado.</param>
        /// <param name="user">Usuario que esta ejecuando la operación.</param>
        public void AddNewPerfil(PerfilInfo perfil, string user)
        {
            using (var context = new MIAPDBEntities())
            {
                var miapPerfil = new MIAP_PERFIL
                {
                    ID_PROYECTO = perfil.Proyecto.IDProyecto,
                    ACTIVO = perfil.EstaActivo,
                    USUARIO_CREACION = user,
                    USUARIO_ACTUALIZACION = user,
                    FECHA_ACTUALIZACION = DateTime.Now,
                    FECHA_CREACION = DateTime.Now,
                    DESCRIPCION = perfil.Descripcion,
                    NOMBRE = perfil.NombrePerfil

                };

                foreach (var permiso in perfil.Permisos)
                {
                    context.MIAP_PERFIL_URL_PERFIL.Add(new MIAP_PERFIL_URL_PERFIL
                    {
                        MIAP_PERFIL = miapPerfil
                        ,
                        ID_PERFIL_URL = permiso.PerfilUrl.IdPerfilUrl
                        ,
                        FECHA_CREACION = DateTime.Now
                        ,
                        USUARIO_CREACION = user
                    });
                }

                context.MIAP_PERFIL.Add(miapPerfil);

                context.SaveChanges();
            }
        }

        /// <summary>
        /// Modifica la información de un perfil .
        /// </summary>
        /// <param name="perfil">Es el perfil al que se le modificará la información.</param>
        /// <param name="user">Usuario que esta ejecutando la operación.</param>
        public void EditPerfil(PerfilInfo perfil, string user)
        {
            using (var context = new MIAPDBEntities())
            {
                var eliminaPermisos = from miapPerfilUrlPerfil in context.MIAP_PERFIL_URL_PERFIL
                                      where miapPerfilUrlPerfil.ID_PERFIL == perfil.IdPerfil
                                      select miapPerfilUrlPerfil;

                // Eliminar lospermisos anteriores. y solo dejamos los que selecciono
                foreach (var miapPerfilUrlPerfil in eliminaPermisos)
                {
                    context.MIAP_PERFIL_URL_PERFIL.Remove(miapPerfilUrlPerfil);
                }
                context.SaveChanges();

                var query = (from miapPerfil in context.MIAP_PERFIL
                             where miapPerfil.ID_PERFIL == perfil.IdPerfil
                             select miapPerfil).SingleOrDefault();
                if (query == null) return;

                query.ACTIVO = perfil.EstaActivo;
                query.NOMBRE = perfil.NombrePerfil;
                query.ID_PROYECTO = (perfil.Proyecto == null) ? (int?)null : perfil.Proyecto.IDProyecto;
                query.DESCRIPCION = perfil.Descripcion;

                query.FECHA_ACTUALIZACION = DateTime.Now;
                query.USUARIO_ACTUALIZACION = user;
                context.SaveChanges();

                foreach (var permiso in perfil.Permisos)
                {
                    context.MIAP_PERFIL_URL_PERFIL.Add(new MIAP_PERFIL_URL_PERFIL
                    {
                        ID_PERFIL = query.ID_PERFIL
                        ,
                        ID_PERFIL_URL = permiso.PerfilUrl.IdPerfilUrl
                        ,
                        FECHA_CREACION = DateTime.Now
                        ,
                        USUARIO_CREACION = user
                    });
                }

                context.SaveChanges();
            }
        }

        /// <summary>
        /// Obtiene los perfiles existentes para un proyecto.
        /// </summary>
        /// <returns>Lista con el id y el nombre de los perfiles.</returns>
        public IList<CatalogoInfo> GetCatalogPerfiles(int? idProyecto)
        {
            IList<CatalogoInfo> result;

            using (var context = new MIAPDBEntities())
            {
                var query = from perfil in context.MIAP_PERFIL
                            where (!idProyecto.HasValue || perfil.ID_PROYECTO == idProyecto)
                            select new CatalogoInfo
                            {
                                IdItem = perfil.ID_PERFIL,
                                Descripcion = perfil.NOMBRE
                            };

                result = query.ToList();
            }

            return result;
        }

        /// <summary>
        /// Verifica la existencia de un perfil.
        /// </summary>
        /// <param name="nombrePerfil">Es el nombre del perfil.</param>
        /// <returns>Indicador de si el perfil existe o no.</returns>
        public bool VerifyExistPerfil(string nombrePerfil)
        {
            MIAP_PERFIL perfilExist = new MIAP_PERFIL();

            using (var context = new MIAPDBEntities())
            {
                var query = (from perfil in context.MIAP_PERFIL
                             where perfil.NOMBRE.Trim().ToLower() == nombrePerfil
                             select perfil).SingleOrDefault();

                perfilExist = query;

                if (perfilExist == null)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
    }
}
